﻿/**********************************************************************
/// <summary>
// Name of File     :   ValidationManager.cs
// Author           :   Parminder Singh
// Create date      :   17th Sep 2011
/// </summary>
************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using System.Text.RegularExpressions;
using System.Collections;

namespace Crystal.CLL
{
    public class ValidationManager
    {
        #region Declare
        public static bool IsButtonClick = false;
        #endregion
        #region ValidationDataType
        public enum ValidationDataType
        {
            Currency,
            Date,
            Double,
            Integer,
            String,
            UInt64,
            Int64
        }
        #endregion

        #region ValidationCompareOperator
        public enum ValidationCompareOperator
        {
            DataTypeCheck,
            Equal,
            GreaterThan,
            GreaterThanEqual,
            LessThan,
            LessThanEqual,
            NotEqual
        }
        #endregion

        #region RegExpressionType
        public enum RegexType
        {
            Email, AlphaNumeric, Telephone, Numeric, Decimal, Double
        }
        #endregion

        #region ValidatableControlConverter
        public class ValidatableControlConverter : ReferenceConverter
        {
            public ValidatableControlConverter(Type type) : base(type) { }
            protected override bool IsValueAllowed(ITypeDescriptorContext context, object value)
            {
                return ((value is TextBox) ||
                        (value is ListBox) ||
                        (value is ComboBox) ||
                        (value is UserControl));
            }
        }
        #endregion

        #region BaseValidator
        public abstract class BaseValidator : System.ComponentModel.Component
        {

            private Control _controlToValidate = null;
            private string _errorMessage = "";
            private Icon _icon = new Icon(typeof(ErrorProvider), "Error.ico");
            private static ErrorProvider _errorProvider = new ErrorProvider();
            private bool _isValid = false;

            [Category("Appearance")]
            [Description("Gets or sets the text for the error message.")]
            [DefaultValue("")]
            public string ErrorMessage
            {
                get { return _errorMessage; }
                set { _errorMessage = value; }
            }

            [Category("Appearance")]
            [Description("Gets or sets the Icon to display ErrorMessage.")]
            public Icon Icon
            {
                get { return _icon; }
                set { _icon = value; }
            }

            [Category("Behaviour")]
            [Description("Gets or sets the input control to validate.")]
            [DefaultValue(null)]
            [TypeConverter(typeof(ValidatableControlConverter))]
            public Control ControlToValidate
            {
                get { return _controlToValidate; }
                set
                {

                    _controlToValidate = value;

                    // Hook up ControlToValidate’s Validating event
                    // at run-time ie not from VS.NET
                    if ((_controlToValidate != null) && (!DesignMode))
                    {
                        _controlToValidate.Validating +=
                          new CancelEventHandler(ControlToValidate_Validating);
                    }
                }
            }

            [Browsable(false)]
            [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
            public bool IsValid
            {
                get { return _isValid; }
                set { _isValid = value; }
            }

            protected abstract bool EvaluateIsValid();

            //public void Validate()
            //{
            //    // Validate control
            //    _isValid = EvaluateIsValid();

            //    // Display an error if ControlToValidate is invalid, using 
            //    // the static ErrorProvider instance
            //    string errorMessage = "";
            //    if (!_isValid)
            //    {
            //        errorMessage = _errorMessage;
            //        _errorProvider.Icon = _icon;
            //    }
            //    _errorProvider.SetError(_controlToValidate, errorMessage);
            //}

            public bool Validate()
            {
                // Validate control
                _isValid = EvaluateIsValid();

                // Display an error if ControlToValidate is invalid, using 
                // the static ErrorProvider instance
                string errorMessage = "";
                if (!_isValid)
                {
                    errorMessage = _errorMessage;
                    _errorProvider.Icon = _icon;
                }
                _errorProvider.SetError(_controlToValidate, errorMessage);
                return _isValid;
            }

            public void ControlToValidate_Validating(object sender, CancelEventArgs e)
            {
                // We don't cancel if invalid since we don't want to force
                // the focus to remain on ControlToValidate if invalid
                if (Validate() == false)
                {
                    if (IsButtonClick)                 // Cancel if Button is clicked
                        e.Cancel = true;
                }
            }
        }
        #endregion

        #region RequiredFieldValidator
        [ToolboxBitmap(typeof(RequiredFieldValidator), "RequiredFieldValidator.ico")]
        public class RequiredFieldValidator : BaseValidator
        {

            private string _initialValue = null;
            private bool _isRequired = true;
            [Category("Behaviour")]
            [DefaultValue(null)]
            [Description("Sets or returns the base value for the validator. The default value is null.")]
            public string InitialValue
            {
                get { return _initialValue; }
                set { _initialValue = value; }
            }
            public bool IsRequired
            {
                get { return _isRequired; }
                set { _isRequired = value; }
            }
            protected override bool EvaluateIsValid()
            {
                if (IsRequired)
                {
                    string controlValue = ControlToValidate.Text.Trim();
                    string initialValue;
                    if (_initialValue == null) initialValue = "";
                    else initialValue = _initialValue.Trim();
                    return (controlValue != initialValue);
                }
                else
                    return true;
            }
        }
        #endregion

        #region BaseCompareValidator
        public abstract class BaseCompareValidator : BaseValidator
        {

            private ValidationDataType _type = ValidationDataType.String;
            private string[] _typeTable = new string[7] {"System.Decimal", 
                                                             "System.DateTime",
                                                             "System.Double",
                                                             "System.Int32",
                                                             "System.String",
                                                             "System.UInt64",
                                                             "System.Int64"
                                                             };

            [Category("Behaviour")]
            [Description("Sets or returns the data type that specifies how to interpret the values being compared.")]
            [DefaultValue(ValidationDataType.String)]
            public ValidationDataType Type
            {
                get { return _type; }
                set { _type = value; }
            }

            protected TypeConverter TypeConverter
            {
                get { return TypeDescriptor.GetConverter(System.Type.GetType(_typeTable[(int)_type])); }
            }

            protected bool CanConvert(string value)
            {
                try
                {
                    TypeConverter _converter = TypeDescriptor.GetConverter(System.Type.GetType(_typeTable[(int)_type]));
                    _converter.ConvertFrom(value);
                    return true;
                }
                catch { return false; }
            }

            protected string Format(string value)
            {
                // If currency
                if (_type == ValidationDataType.Currency)
                {
                    // Convert to decimal format ie remove currency formatting characters
                    return Regex.Replace(value, "[$ .]", "");
                }
                return value;
            }
        }
        #endregion

        #region CompareValidator
        [ToolboxBitmap(typeof(CompareValidator), "CompareValidator.ico")]
        public class CompareValidator : BaseCompareValidator
        {

            private string _valueToCompare = "";
            private Control _controlToCompare = null;
            private ValidationCompareOperator _operator = ValidationCompareOperator.Equal;

            [TypeConverter(typeof(ValidatableControlConverter))]
            [Category("Behaviour")]
            [Description("Gets or sets the input control to compare with the input control being validated.")]
            [DefaultValue(null)]
            public Control ControlToCompare
            {
                get { return _controlToCompare; }
                set { _controlToCompare = value; }
            }

            [Category("Behaviour")]
            [Description("Gets or sets the comparison operation to perform.")]
            [DefaultValue(null)]
            public ValidationCompareOperator Operator
            {
                get { return _operator; }
                set { _operator = value; }
            }

            [Category("Behaviour")]
            [Description("Gets or sets a constant value to compare with the value entered by the user into the input control being validated.")]
            [DefaultValue("")]
            public string ValueToCompare
            {
                get { return _valueToCompare; }
                set { _valueToCompare = value; }
            }

            protected override bool EvaluateIsValid()
            {
                // Don't validate if empty, unless required
                if (ControlToValidate.Text.Trim() == "") return true;

                // Can't evaluate if missing ControlToCompare and ValueToCompare
                if ((_controlToCompare == null) && (_valueToCompare == "")) throw new Exception("The ControlToCompare property cannot be blank.");

                // Validate and convert CompareFrom
                string formattedCompareFrom = Format(ControlToValidate.Text);
                bool canConvertFrom = CanConvert(formattedCompareFrom);
                if (canConvertFrom)
                {
                    if (_operator == ValidationCompareOperator.DataTypeCheck) return canConvertFrom;
                }
                else return false;
                object compareFrom = TypeConverter.ConvertFrom(formattedCompareFrom);

                // Validate and convert CompareTo
                string formattedCompareTo = Format(((_controlToCompare != null) ? _controlToCompare.Text : _valueToCompare));
                if (!CanConvert(formattedCompareTo)) throw new Exception("The value you are comparing to cannot be converted to the specified Type.");
                object compareTo = TypeConverter.ConvertFrom(formattedCompareTo);

                // Perform comparison eg ==, >, >=, <, <=, !=
                int result = Comparer.Default.Compare(compareFrom, compareTo);
                switch (_operator)
                {
                    case ValidationCompareOperator.Equal:
                        return (result == 0);
                    case ValidationCompareOperator.GreaterThan:
                        return (result > 0);
                    case ValidationCompareOperator.GreaterThanEqual:
                        return (result >= 0);
                    case ValidationCompareOperator.LessThan:
                        return (result < 0);
                    case ValidationCompareOperator.LessThanEqual:
                        return (result <= 0);
                    case ValidationCompareOperator.NotEqual:
                        return ((result != 0));
                    default:
                        return false;
                }
            }
        }
        #endregion

        #region RegularExpressionValidator
        [ToolboxBitmap(typeof(RegularExpressionValidator), "Bullet.ico")]
        public class RegularExpressionValidator : BaseValidator
        {

            private string _validationExpression = "";
            public bool _isRequired = true;
            [Category("Behaviour")]
            [Description("Gets or sets the regular expression that determines the pattern used to validate a field.")]
            [DefaultValue("")]
            public string ValidationExpression
            {
                get { return _validationExpression; }
                set { _validationExpression = value; }
            }
            public bool IsRequired
            {
                get { return _isRequired; }
                set { _isRequired = value; }
            }

            protected override bool EvaluateIsValid()
            {
                // Don't validate if empty
                if (_isRequired)
                    if (ControlToValidate.Text.Trim() == "") return false;
                // Successful if match matches the entire text of ControlToValidate
                if (ControlToValidate.Text.Length > 0)
                {
                    string field = ControlToValidate.Text.Trim();
                    return Regex.IsMatch(field, _validationExpression.Trim());
                }
                else return true;
            }
        }
        #endregion

        #region RegularExpressionTypes
        public static string regexString(RegexType type)
        {
            if (type == RegexType.Email)
                return @"^([a-zA-ZÀ-ÿ0-9_\-\.]+)@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$";

            else if (type == RegexType.AlphaNumeric)
                return @"^(?=.*\p{L})(?=.*\p{N})(?=.*[^\p{L}\p{N}]).{6,10}$";//^(?=.*[0-9])(?=.*[a-z]).{6,10}$";  //"@"[a-zA-Z0-9_\-\.]{6,10}";//^([a-zA-Z0-9_\-\.]+){6,10}";//\b\w{6,10}\b";
            else if (type == RegexType.Telephone)
                return @"^(\+)?\d+$";

            else if (type == RegexType.Numeric)
                return @"^\d{1,5}$";

            else if (type == RegexType.Decimal)
                return @"^\d{1,3}(\.\d{1,3})?$";

            else if (type == RegexType.Double)
                return @"^\d{1,15}(\.\d{1,3})?$";
            return string.Empty;


        }
        #endregion

        #region RangeValidator
        [ToolboxBitmap(typeof(RangeValidator), "RangeValidator.ico")]
        public class RangeValidator : BaseCompareValidator
        {

            private string _minimumValue = "";
            private string _maximumValue = "";

            [Category("Behaviour")]
            [Description("Sets or returns the value of the control that you are validating, which must be greater than or equal to the value of this property. The default value is an empty string (\"\").")]
            [DefaultValue("")]
            public string MinimumValue
            {
                get { return _minimumValue; }
                set { _minimumValue = value; }
            }

            [Category("Behaviour")]
            [Description("Sets or returns the value of the control that you are validating, which must be less than or equal to the value of this property. The default value is an empty string (\"\").")]
            [DefaultValue("")]
            public string MaximumValue
            {
                get { return _maximumValue; }
                set { _maximumValue = value; }
            }

            protected override bool EvaluateIsValid()
            {
                // Don't validate if empty, unless required

                if (ControlToValidate.Text.Trim() == "") return true;
                //string OriginalValues = ControlToValidate.Text;
                //string ChangedValues = string.Empty;
                //if (OriginalValues.ToString().Contains(","))
                //{
                //    ChangedValues = ControlToValidate.Text.ToString().Replace(",", "");
                //}
                // Validate and convert Minimum
                if (_minimumValue.Trim() == "") throw new Exception("MinimumValue must be provided.");
                string formattedMinimumValue = Format(_minimumValue.Trim());
                if (!CanConvert(formattedMinimumValue)) throw new Exception("MinimumValue cannot be converted to the specified Type.");
                object minimum = TypeConverter.ConvertFrom(formattedMinimumValue);

                // Validate and convert Maximum
                if (_maximumValue.Trim() == "") throw new Exception("MaximumValue must be provided.");
                string formattedMaximumValue = Format(_maximumValue.Trim());
                if (!CanConvert(formattedMaximumValue)) throw new Exception("MaximumValue cannot be converted to the specified Type.");
                object maximum = TypeConverter.ConvertFrom(formattedMaximumValue);

                // Check minimum <= maximum
                if (Comparer.Default.Compare(minimum, maximum) > 0) throw new Exception("MinimumValue cannot be greater than MaximumValue.");

                // Check and convert ControlToValue
                string formattedValue = Format(ControlToValidate.Text.Trim().Replace(",", ""));
                if (!CanConvert(formattedValue)) return false;
                object value = TypeConverter.ConvertFrom(formattedValue);

                // Validate value's range (minimum <= value <= maximum)
                return ((Comparer.Default.Compare(minimum, value) <= 0) &&
                  (Comparer.Default.Compare(value, maximum) <= 0));
            }
        }
        #endregion
    }
}
